Over-the-Air NVIDIA Jetson - RAUC Advanced Topics and Troubleshooting

From RidgeRun Developer Wiki

Follow Us On Twitter LinkedIn Email Share this page




NVIDIA partner logo NXP partner logo







RAUC on NVIDIA Jetson: Advanced Topics and Troubleshooting

This page documents advanced integration topics and the main issues encountered during bring-up and A/B update validation.

It covers:

  • Adaptive updates
  • Persistent state design
  • Common bundle, service, and bootloader failures
  • Custom backend failure modes
  • Practical troubleshooting notes

Enabling RAUC Adaptive Updates

After validating the signed A/B update flow, the next step was to prepare the integration for adaptive updates.

The purpose of this change was to make RAUC reuse persistent update metadata across both rootfs slots, reducing unnecessary data transfer and aligning the design with a production-ready A/B layout.

What Had to Change

The adaptive update path required three essential changes:

  • use verity bundles instead of plain
  • enable adaptive=block-hash-index for the rootfs image
  • move RAUC runtime state to a shared persistent location

In practice, this meant updating both the bundle recipe and the RAUC runtime configuration.

Bundle Recipe Changes

The original bundle recipe still used:

RAUC_BUNDLE_FORMAT = "plain"

This was updated to:

RAUC_BUNDLE_FORMAT = "verity"
RAUC_SLOT_rootfs[adaptive] = "block-hash-index"

These two lines are the key Yocto-side changes that make the bundle adaptive-ready.

Persistent State Requirement

The initial configuration stored RAUC status under:

statusfile=/var/lib/rauc/status

That worked for the basic integration, but it was not suitable for adaptive updates because /var/lib/rauc belongs to the currently booted rootfs.

To solve this, the configuration was changed to:

statusfile=/data/rauc/status
data-directory=/data/rauc

This ensures that RAUC state is shared across slot A and slot B.

Backend Alignment

The custom Jetson bootloader backend was also originally using /var/lib/rauc.

To keep the system consistent, its internal state directory was moved to:

/data/rauc

This keeps:

  • RAUC status
  • backend state
  • slot metadata

in the same persistent location.

Persistent /data Mount

A shared state directory only works if it is actually backed by persistent storage.

For that reason, a dedicated mount unit was added so that the Jetson persistent partition (UDA) is mounted on:

/data

Without this step, /data/rauc could still be created inside the rootfs, defeating the purpose of adaptive state sharing.

Main Problems Encountered

Error: Nothing PROVIDES 'demo-bundle'

Cause:

The recipe was not in a layer path that BitBake was parsing.

Fix:

Ensure directory structure matches the layer's BBFILES expectations.

Error: signature verification failed

Cause:

Target CA did not match the signing CA.

Fix:

Rebuild the image including the correct ca.cert.pem and reflash.

Error: RAUC service not starting

Common causes:

  • Missing bootloader=
  • Invalid bootloader backend
  • Missing /var/lib/rauc
  • Missing kernel cmdline parameters

Resolved by:

  • Setting bootloader=noop initially
  • Adding root= and rauc.slot= to cmdline
  • Creating the status directory

Error: unsupported custom backend commands

Cause:

The first version of the backend only implemented:

  • get-primary
  • set-primary
  • get-booted

But RAUC also requires:

  • get-state
  • set-state

Fix:

Extend the backend to implement slot state persistence.

Error: boot status remains bad

Cause:

The backend either:

  • did not implement get-state / set-state, or
  • always returned bad

Fix:

Persist slot state under backend-managed files and expose them correctly through the custom backend interface.

Error: target still uses RAUC Test CA

Cause:

The image still installed the default example CA rather than the project-generated CA.

Fix:

Copy the generated CA into:

layers/meta-tegrademo/recipes-core/rauc/rauc-conf/files/ca.cert.pem

Then rebuild and reflash.

Error: cmdline and mounted root do not match

Cause:

rauc.slot= may indicate one slot while root= or the actual mounted / still points to another.

Fix:

Always verify:

findmnt -n -o SOURCE /
cat /proc/cmdline

The active root device and slot identifier must be consistent.

Practical Debugging Commands

Service and Logs

systemctl status rauc.service --no-pager -l
journalctl -xeu rauc.service --no-pager

Slot Validation

rauc status
rauc status --output-format=json-pretty

Cmdline Validation

cat /proc/cmdline | tr ' ' '\n' | egrep '^(root=|rauc\.slot=)'
findmnt -n -o SOURCE /

Certificate Validation

openssl x509 -in /etc/rauc/ca.cert.pem -noout -subject -issuer -fingerprint -sha256

Backend Validation

/usr/lib/rauc/backend/jetson-extlinux get-primary
/usr/lib/rauc/backend/jetson-extlinux get-booted
/usr/lib/rauc/backend/jetson-extlinux get-state A
/usr/lib/rauc/backend/jetson-extlinux get-state B

Current Limitations

Even with the custom backend, the integration remains relatively simple compared to full bootloader-native A/B systems.

Current limitations include:

  • extlinux-based slot control rather than native Jetson boot slot handling
  • no automatic rollback policy beyond what is manually implemented
  • state persistence relies on the backend implementation
  • adaptive update support requires a persistent shared data partition